package ua.kpi_java_training.nikishov.module1;

import java.util.Scanner;
import java.util.ArrayList;

/**
 * Class performs long division with two numbers entered
 * with keyboard, and prints all the intermediate results
 * to the console.
 *
 * @author Alexey Nikishov
 */
public class LongDivision {
    private static final int NUMERAL_SYSTEM = 10;
    private static final int NUMBER_OF_VALUES_IN_STEP = 2;
    private static Scanner sc = new Scanner(System.in);
    /**
     * Contains the digits of which consists dividend.
     */
    private static ArrayList<Integer> divDigits = new ArrayList<Integer>();
    /**
     * Contains intermediate results of long division
     */
    private static ArrayList<Integer> intermediateResults = new ArrayList<Integer>();
    private static int dividend = 1;
    private static int divisor = 1;
    private static int quotient = 0;

    public static void main(String[] args) {
        input();
        splitDivIntoDigits(dividend);
        doDivision();
        generalOutput();
    }

    /**
     * Reads the integer dividend and divisor, different from zero, from the keyboard.
     */
    public static void input() {
        dividend = inputNumber("Input dividend:");
        while (true) {
           divisor = inputNumber("Input divisor:");
            if (!(divisor == 0)) {
                break;
            }
            System.out.println("Divisor can't be zero.");
        }
    }

    /**
     * Reads integer number from the keyboard.
     *
     * @param  prompt is a hint to the user, which is output to the console.
     * @return integer number, entered from the keyboard.
     */
    public static int inputNumber(String prompt) {
        System.out.println(prompt);
        while (!sc.hasNextInt()) {
            System.out.println("It must be integer number.");
            sc.next();
        }
        return sc.nextInt();
    }

    /**
     * Splits number into integer digits and writes them to the collection.
     * @param  dividend is a number, which is split.
     * @return collection which contains digits of number, that was split.
     */
    public static ArrayList<Integer> splitDivIntoDigits(int dividend) {
        if (dividend == 0) {
            divDigits.add(0);
        }
        while (dividend > 0) {
            divDigits.add(dividend % NUMERAL_SYSTEM);
            dividend /= NUMERAL_SYSTEM;
        }
        return divDigits;
    }

    /**
     * Allocates part in the dividend, that can be divided by divisor,
     * performs division, writes intermediate results and calculates
     * the quotient.
     */
    public static void doDivision() {
        int currentDiv = divDigits.remove(divDigits.size() - 1);
        while (true) {
            if (currentDiv >= divisor) {
                currentDiv = doIntermediateDivision(currentDiv);
            } else if (!divDigits.isEmpty()) {
                currentDiv = currentDiv * 10 + divDigits.remove(divDigits.size() - 1);
                if (currentDiv < divisor && quotient != 0) {
                    quotient *= 10;
                }
            } else {
                intermediateResults.add(currentDiv);
                break;
            }
        }
    }

    /**
     * Divides the current intermediate dividend by the divisor and writes
     * received values.
     *
     * @param  currentDiv the part of dividend which can be divided by divisor.
     * @return modulo from current intermediate division
     */
    public static int doIntermediateDivision(int currentDiv) {
        intermediateResults.add(currentDiv);
        quotient = quotient*10 + currentDiv / divisor;
        intermediateResults.add((currentDiv / divisor) * divisor);
        currentDiv %= divisor;
        return currentDiv;
    }

    /**
     * Prints the specified number of characters "-".
     *
     * @param number the number of printed characters "-".
     */
    public static void printLine(int number) {
        System.out.printf(String.format("%0"+getNumberLength(number)+"d", 0).replace('0','-'));
        System.out.println();
    }

    /**
     * Prints the specified number of white spaces.
     *
     * @param number the number of printed white spaces.
     */
    public static void printSpaces(int number) {
        System.out.printf((number == 0) ? "" : String.format("%" + number + "s", ""));
    }

    /**
     * Gets length of specified number.
     *
     * @param  number the number, which length is searched.
     * @return the length of specified number.
     */
    public static int getNumberLength(int number) {
        return String.valueOf(number).length();
    }

    /**
     * Output the header, column of division and quotient.
     */
    public static void generalOutput() {
        System.out.println(dividend + "|" + divisor);
        outputStagesOfDivision();
        System.out.print("Quotient = " + quotient);
    }

    /**
     * Outputs column of division.
     */
    public static void outputStagesOfDivision() {
        for (int count = 1; count < intermediateResults.size(); count++) {
            printSpaces(count / NUMBER_OF_VALUES_IN_STEP);
            System.out.println(intermediateResults.get(count));
            if (count % 2 == 1) {
                printSpaces(count / NUMBER_OF_VALUES_IN_STEP);
                printLine(intermediateResults.get(count));
            }
        }
    }


}
